////////////////////////////////////////////////////////////////////
//
// NO_Value.h header for the NO_Object class.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#ifndef NO_Value_H
#define NO_Value_H

//////////////////////////////////////////////////////////////////////////
#include "NO_Includes.h"

//////////////////////////////////////////////////////////////////////////
class NO_OArchive;
class NO_IArchive;
template <class T> class NO_TypeObject;
template <class T> class NO_Constructor;
template <class T> class NO_Copy;
class NO_Dummy{};

//////////////////////////////////////////////////////////////////////////
// class NO_Value definition
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_Value  
{
	//////////////////////////////////////////////////////////////////////////
	typedef NO_IDSet<NO_Value, 4>	ObjectSet;
	typedef ObjectSet::iterator		ObjectSetIter;

public:
	//////////////////////////////////////////////////////////////////////////
	// modify
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	void setName(const std::string& name);
	void setName(const NO_Int8* name);

	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&  getType (void);
	virtual const NO_Type&  getDynamicType (void) = 0;

	//////////////////////////////////////////////////////////////////////////
	virtual NO_UInt32	getID			(void) = 0;
	virtual NO_UInt32	getNum			(void) = 0;
	virtual NO_Boolean	hasData			(void) = 0;
	virtual NO_Boolean	getIsConstructed(void) = 0;
	
protected:
	//////////////////////////////////////////////////////////////////////////
	// friends
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	friend class NO_Object;
	friend class NO_ObjectIter;

	//////////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////
	NO_Value(const NO_Type& type);
	virtual ~NO_Value();

	//////////////////////////////////////////////////////////////////////////
	NO_Value(void);
	NO_Value(const NO_Value& rhs);
	NO_Value& operator= (const NO_Value& rhs);

	//////////////////////////////////////////////////////////////////////////
	// modify
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	void setDependent(NO_Value*);

	//////////////////////////////////////////////////////////////////////////
	// var
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	static ObjectSet objectSet;

	//////////////////////////////////////////////////////////////////////////
	NO_Value* depend;
	std::string* name;
	NO_UInt32 numRef;
	const NO_Type& type;
};

//////////////////////////////////////////////////////////////////////////
// class NO_TypedData definition
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ValueImpl : public NO_Value 
{
public:
	//////////////////////////////////////////////////////////////////////////
	// retrieve
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	virtual T* getObject(void) {return object;}

	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&  getDynamicType (void){if (object){return NO_TypeID<>::type(typeid(*object));}return type;}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_UInt32	getID			(void) {return (reinterpret_cast<size_t>(object)%(1<<31));}
	virtual NO_UInt32	getNum			(void) {return num;}
	virtual NO_Boolean	hasData			(void) {return object!=0;}
	virtual NO_Boolean	getIsConstructed(void) {return 0;}

protected:
	//////////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	NO_ValueImpl(const NO_Type& type):NO_Value(type),object(0),num(0){}

	//////////////////////////////////////////////////////////////////////////
	NO_ValueImpl& operator=(const NO_ValueImpl& rhs){}

	//////////////////////////////////////////////////////////////////////////
	T* object;
	NO_UInt32 num;
};

//////////////////////////////////////////////////////////////////////////
// class NO_ConstructValue definition
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ConstructValue : public NO_ValueImpl<T> 
{
private:
	//////////////////////////////////////////////////////////////////////////
	friend class NO_TypeObject<T>;
	friend class NO_Constructor<T>;

	//////////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_ConstructValue(T* o, NO_UInt32 n=1) : NO_ValueImpl<T>(NO_TypeID<T>::type())
	{
		switch (n)
		{
		case 0 : std::exception("Can not allocate array of size 0.");
		default: object = o;	break;
		}
		num = n;

		objectSet.insert(this);
	}

	//////////////////////////////////////////////////////////////////////
	virtual ~NO_ConstructValue()
	{
		objectSet.erase(this);
		
		switch (num)
		{
		case 1 : delete object;			break;
		default: delete [num] object;	break;
		}
	}
		
	//////////////////////////////////////////////////////////////////////
	virtual NO_Boolean	getIsConstructed	(void){return 1;}
};

//////////////////////////////////////////////////////////////////////////
// class NO_CloneData definition
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_CopyValue : public NO_ValueImpl<T> 
{
public:
	//////////////////////////////////////////////////////////////////////////
	//friends
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	friend class NO_Copy<T>;

	//////////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_CopyValue(T const & rhs) : NO_ValueImpl<T>(NO_TypeID<T>::type())
	{
		object = new T(rhs);
		num = 1;
	}

	//////////////////////////////////////////////////////////////////////
	virtual ~NO_CopyValue()
	{
		delete object;
	}
};

//////////////////////////////////////////////////////////////////////////
// class NO_TypedData definition
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ReplaceValue : public NO_ValueImpl<T> 
{
public:
	//////////////////////////////////////////////////////////////////////////
	// con/destruction
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////
	NO_ReplaceValue(NO_UInt32 n=1) : NO_ValueImpl<T>(NO_TypeID<T>::type())
	{
		switch (n)
		{
		case 0: std::exception("Can not allocate array of size 0.");
		case 1: object = new T; break;
		default: object = new T[n];  break;
		}
		num = n;
	}
};

//////////////////////////////////////////////////////////////////////////
// class NO_TypedData definition
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ReferenceValue : public NO_ValueImpl<T> 
{
public:
	//////////////////////////////////////////////////////////////////////
	// operators
	//////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////
	NO_ReferenceValue(T* o, NO_Value* d, NO_UInt32 n = 1)
	:NO_ValueImpl<T>(NO_TypeID<T>::type())
	{
		object = o; num = n;
		if(!d){return;}
		setDependent(d);
	}
};

#endif 
